package jmine.tec.web.wicket.component.table.resource;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

import jmine.tec.services.api.export.ExportActor;
import jmine.tec.services.io.ServicesPageBean;
import jmine.tec.web.wicket.BeanReference;
import jmine.tec.web.wicket.resource.DiskStoreResource;
import jmine.tec.web.wicket.resource.InMemoryResourceStore;
import jmine.tec.web.wicket.resource.ResourceStore;

import org.apache.commons.io.IOUtils;
import org.apache.wicket.util.resource.IResourceStream;
import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
import org.apache.wicket.util.time.Time;

import bancosys.tec.services.input.driver.XLSServiceWriter;

/**
 * {@link IResourceStream} para a exportação de serviços.
 * 
 * @author Rafael Volpato
 * @date Aug 8, 2011
 */
public class ServiceXLSResourceStream implements IResourceStream {

    private final BeanReference<? extends ExportActor> exportActorRef;

    private InputStream input;

    private Locale locale;

    private final Time time = Time.now();

    private List<?> targets;

    private ResourceStore resourceStore;

    /**
     * Construtor.
     * 
     * @param exportActorRef spring reference to {@link ExportActor}
     */
    public ServiceXLSResourceStream(BeanReference<? extends ExportActor> exportActorRef) {
        this.exportActorRef = exportActorRef;
    }

    /**
     * Define a lista de targets que serão exportados.
     * 
     * @param targets a lista de targets que serão exportados
     */
    public void setTargets(List<?> targets) {
        this.targets = targets;
        this.resourceStore = null;
    }

    /**
     * {@inheritDoc}
     */
    public void close() throws IOException {
        IOUtils.closeQuietly(this.input);
	this.input = null;
    }

    /**
     * Devolve o report 'as is'
     * 
     * @return InputStream
     */
    private InputStream getServicesInputStream() {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        XLSServiceWriter serviceWriter = new XLSServiceWriter();
        ServicesPageBean pageBean = new ServicesPageBean();
        pageBean.setServices(this.exportActorRef.get().export(this.targets));
        try {
            serviceWriter.writeServices(Collections.singletonList(pageBean), bout);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
        return new ByteArrayInputStream(bout.toByteArray());
    }

    /**
     * 
     */
    public synchronized void init() {
        if (this.resourceStore != null) {
            return;
        }
        try {
            this.resourceStore = new DiskStoreResource(this.getServicesInputStream(), true);
        } catch (IOException e) {
            try {
                this.resourceStore = new InMemoryResourceStore(this.getServicesInputStream(), false);
            } catch (IOException e1) {
                throw new IllegalStateException(e);
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public String getContentType() {
        return "application/vnd.ms-excel";
    }

    /**
     * {@inheritDoc}
     */
    public InputStream getInputStream() throws ResourceStreamNotFoundException {
        if (this.input != null) {
            return this.input;
        }
        this.init();
        try {
            this.input = this.resourceStore.openNew();
            return this.input;
        } catch (IOException e) {
            return this.getServicesInputStream();
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.apache.wicket.util.resource.IResourceStream#length()
     */
    public long length() {
        this.init();
        return this.resourceStore.length();
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.apache.wicket.util.watch.IModifiable#lastModifiedTime()
     */
    public Time lastModifiedTime() {
        return this.time;
    }

    /**
     * @return the locale
     */
    public Locale getLocale() {
        return this.locale;
    }

    /**
     * @param locale the locale to set
     */
    public void setLocale(Locale locale) {
        this.locale = locale;
    }
}
